import React, { useCallback, useMemo, useRef, useState, useEffect } from 'react'
import { LeftOutline, SoundOutline } from 'antd-mobile-icons'
import { Toast } from 'antd-mobile'
import styles from './index.module.css'

type ChatMessage = {
    role: 'system' | 'user' | 'assistant'
    content: string
    attachments?: { kind: 'image' | 'file' | 'audio', url?: string, name: string, size?: number, durationMs?: number }[]
}

const DEEPSEEK_API_URL = 'https://openapi.youdao.com/llmgateway/api/v1/chat/completions'

function Index() {
    const [messages, setMessages] = useState<ChatMessage[]>([])
    const [input, setInput] = useState('')
    const [isLoading, setIsLoading] = useState(false)
    const [isHumanOnline, setIsHumanOnline] = useState(false)
    const wsRef = useRef<WebSocket | null>(null)
    const lastUserTextRef = useRef<string | null>(null)
    const mediaRecorderRef = useRef<MediaRecorder | null>(null)
    const [isRecording, setIsRecording] = useState(false)
    const [sessionId] = useState<string>(() => {
        try {
            const fromUrl = new URLSearchParams(location.search).get('sessionId')
            return fromUrl || `sess_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
        } catch {
            return `sess_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
        }
    })
    const containerRef = useRef<HTMLDivElement | null>(null)
    const textareaRef = useRef<HTMLInputElement | null>(null)
    const imageInputRef = useRef<HTMLInputElement | null>(null)
    const fileInputRef = useRef<HTMLInputElement | null>(null)
    const [showEmoji, setShowEmoji] = useState(false)
    const [showVoice, setShowVoice] = useState(false)
    const [attachments, setAttachments] = useState<{ id: string, file: File, url?: string, kind: 'image' | 'file' | 'audio' }[]>([])

    const apiKey = useMemo(() => {
        // Prefer env var; fallback to provided demo key
        return import.meta.env?.VITE_DEEPSEEK_API_KEY || '0736476cd1af0f62'
    }, [])

    const scrollToBottom = useCallback(() => {
        requestAnimationFrame(() => {
            const el = containerRef.current
            if (el) el.scrollTop = el.scrollHeight
        })
    }, [])

    const sendMessage = useCallback(async () => {
        const content = input.trim()
        if ((content.length === 0 && attachments.length === 0) || isLoading) return
        if (!apiKey) {
            alert('Missing API key. Please set VITE_DEEPSEEK_API_KEY in .env')
            return
        }

        const userMessage: ChatMessage = {
            role: 'user',
            content,
            attachments: attachments.map((a) => ({
                kind: a.kind,
                url: a.url,
                name: a.file.name,
                size: a.file.size,
            }))
        }
        const baseMessages: ChatMessage[] = [
            { role: 'system', content: '你是一个专业的中文客服助理，请默认使用简体中文进行交流和回答。除非用户明确要求其他语言，否则始终用中文回复。回复应简洁、友好、可执行。' },
            ...messages,
            userMessage,
        ]

        setMessages((prev) => [...prev, userMessage, { role: 'assistant', content: '' }])
        setInput('')
        // 清空本地待发送的附件列表（不立即 revoke 以保证聊天区能正常显示 blob 预览）
        setAttachments([])
        setIsLoading(true)
        scrollToBottom()

        // If human is connected, do not call AI; relay to human agent over WS
        if (isHumanOnline) {
            setMessages((prev) => prev.slice(0, -1))
            // send over websocket if available
            try {
                if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
                    wsRef.current.send(JSON.stringify({ type: 'user_message', sessionId, text: content }))
                    lastUserTextRef.current = content
                    // local rule-based auto-reply when using generic echo server
                    const normalized = content.trim()
                    if (normalized === '你好') {
                        setMessages((prev) => [...prev, { role: 'assistant', content: '你好呀! 小冯很高心为你服务。' }])
                        scrollToBottom()
                    } else if (normalized === '再见') {
                        setMessages((prev) => [...prev, { role: 'assistant', content: '感谢您的提问。再见！' }])
                        scrollToBottom()
                    }
                }
            } catch { /* ignore */ }
            setIsLoading(false)
            return
        }

        try {
            const controller = new AbortController()
            const response = await fetch(DEEPSEEK_API_URL, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${apiKey}`,
                },
                body: JSON.stringify({
                    model: 'deepseek-r1-250120',
                    messages: baseMessages,
                    stream: true,
                    max_tokens: 1000,
                    stream_options: { include_usage: true },
                    presence_penalty: 0,
                    frequency_penalty: 0,
                    temperature: 0,
                    top_p: 0,
                }),
                signal: controller.signal,
            })

            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`)
            }

            const reader = response.body?.getReader()
            if (!reader) throw new Error('No response body')

            let buffer = ''
            while (true) {
                const { done, value } = await reader.read()
                if (done) break

                buffer += new TextDecoder().decode(value)
                const lines = buffer.split('\n')
                buffer = lines.pop() || ''

                for (const line of lines) {
                    if (line.startsWith('data: ')) {
                        const data = line.slice(6)
                        if (data === '[DONE]') {
                            setIsLoading(false)
                            scrollToBottom()
                            return
                        }

                        try {
                            const parsed = JSON.parse(data)
                            if (parsed.choices?.[0]?.delta?.content) {
                                const content = parsed.choices[0].delta.content
                                setMessages((prev) => {
                                    const newMessages = [...prev]
                                    const lastMessage = newMessages[newMessages.length - 1]
                                    if (lastMessage && lastMessage.role === 'assistant') {
                                        lastMessage.content += content
                                    }
                                    return newMessages
                                })
                                scrollToBottom()
                            }
                        } catch (e) {
                            console.warn('Failed to parse SSE data:', e)
                        }
                    }
                }
            }
        } catch (error: unknown) {
            if (error instanceof Error && error.name === 'AbortError') {
                console.log('Request aborted')
            } else {
                console.error('Error:', error)
                alert('发送失败，请重试')
            }
        } finally {
            setIsLoading(false)
            scrollToBottom()
        }
    }, [input, attachments, isLoading, apiKey, messages, isHumanOnline, sessionId, scrollToBottom])

    const onKeyDown = useCallback((e: React.KeyboardEvent) => {
        if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault()
            sendMessage()
        }
    }, [sendMessage])

    const addEmoji = useCallback((emoji: string) => {
        setInput(prev => prev + emoji)
    }, [])

    const onPickImages = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
        const files = Array.from(e.target.files || [])
        if (files.length === 0) return

        const newAttachments = files.map(file => {
            const url = URL.createObjectURL(file)
            return {
                id: `${Date.now()}-${Math.random()}`,
                file,
                url,
                kind: 'image' as const
            }
        })

        setAttachments(prev => [...prev, ...newAttachments])
        setTimeout(() => { sendMessage() }, 0)
    }, [sendMessage])

    const onPickFiles = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
        const files = Array.from(e.target.files || [])
        if (files.length === 0) return

        const newAttachments = files.map(file => {
            const url = URL.createObjectURL(file)
            return {
                id: `${Date.now()}-${Math.random()}`,
                file,
                url,
                kind: 'file' as const
            }
        })

        setAttachments(prev => [...prev, ...newAttachments])
    }, [])

    const removeAttachment = useCallback((id: string) => {
        setAttachments(prev => {
            const attachment = prev.find(a => a.id === id)
            if (attachment?.url) {
                URL.revokeObjectURL(attachment.url)
            }
            return prev.filter(a => a.id !== id)
        })
    }, [])

    // WebSocket connection for human agent
    useEffect(() => {
        if (isHumanOnline) {
            // Connect to WebSocket server
            const ws = new WebSocket('wss://echo.websocket.org')
            wsRef.current = ws

            ws.onopen = () => {
                console.log('WebSocket connected')
                ws.send(JSON.stringify({ type: 'join', sessionId }))
            }

            ws.onmessage = (event) => {
                try {
                    const data = JSON.parse(event.data)
                    if (data.type === 'agent_message' && data.text) {
                        setMessages(prev => [...prev, { role: 'assistant', content: data.text }])
                        scrollToBottom()
                    }
                } catch (e) {
                    console.warn('Failed to parse WebSocket message:', e)
                }
            }

            ws.onerror = (error) => {
                console.error('WebSocket error:', error)
            }

            ws.onclose = () => {
                console.log('WebSocket disconnected')
            }

            return () => {
                ws.close()
            }
        } else {
            if (wsRef.current) {
                wsRef.current.close()
                wsRef.current = null
            }
        }
    }, [isHumanOnline, sessionId, scrollToBottom])

    return (
            <div className={styles.container}>
                <div className={styles.header}>
                    <LeftOutline className={styles.headerBtn} onClick={() => window.history.back()} />
                    <div className={styles.headerTitle}>DeepSeek 智能客服</div>
                    {isHumanOnline ? (
                        <button className={styles.headerBtn2} onClick={() => setIsHumanOnline(false)}>结束人工</button>
                    ) : (
                        <button className={styles.headerBtn2} onClick={() => {
                            setIsHumanOnline(true)
                            Toast.show({
                                content: '已为您转接医生，请稍候',
                                duration: 2000,
                            })
                        }}>转人工</button>
                    )}
                </div>
                <div ref={containerRef} className={styles.scroll}>
                    <div className={styles.inner}>
                        {messages.length === 0 && (
                            <div className={styles.emptyHint}>开始对话吧，我是 DeepSeek 智能客服。</div>
                        )}
                        {messages.map((m, i) => {
                            const hasImages = !!m.attachments && m.attachments.some(a => a.kind === 'image' && a.url)
                            const hasText = (m.content || '').trim().length > 0
                            const contentCol = (
                                <div style={{ display: 'flex', flexDirection: 'column', alignItems: m.role === 'user' ? 'flex-end' : 'flex-start', gap: 6, width: '100%' }}>
                                    {hasText && (
                                        <div className={`${styles.bubble} ${m.role === 'user' ? styles.bubbleUser : styles.bubbleAssistant}`}>
                                            {m.content}
                                        </div>
                                    )}
                                    {m.attachments && hasImages && (
                                        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
                                            {m.attachments?.filter(a => a.kind === 'image' && a.url).map((att, idx) => (
                                                <img key={idx} src={att.url as string} alt={att.name} style={{ width: 220, height: 220, objectFit: 'cover', borderRadius: 10, border: '1px solid #eee', background: '#fff' }} />
                                            ))}
                                        </div>
                                    )}
                                    {m.attachments && m.attachments.some(a => a.kind === 'audio' && a.url) && (
                                        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                                            {m.attachments?.filter(a => a.kind === 'audio' && a.url).map((att, idx) => (
                                                <audio key={idx} controls src={att.url} style={{ width: 280 }} />
                                            ))}
                                        </div>
                                    )}
                                </div>
                            )
  return (
                                <div key={i} className={`${styles.msgRow} ${m.role === 'user' ? styles.msgRowUser : ''}`}>
                                    {m.role !== 'user' && (<div className={styles.avatar}>A</div>)}
                                    {contentCol}
                                    {m.role === 'user' && (<div className={`${styles.avatar} ${styles.avatarUser}`}>U</div>)}
    </div>
                            )
                        })}
                    </div>
                </div>
                <div className={styles.footer}>
                    <div className={styles.footerInner}>
                        {isHumanOnline && (
                            <div className={styles.statusBar}>已转接人工客服，AI 已暂停回复。</div>
                        )}
                        {attachments.length > 0 && (
                            <div className={styles.attachList}>
                                {attachments.map((att) => (
                                    <div key={att.id} className={styles.attachItem}>
                                        {att.kind === 'image' && att.url ? (
                                            <img className={styles.thumbImg} src={att.url} alt={att.file.name} />
                                        ) : (
                                            <div className={styles.thumbFile}>FILE</div>
                                        )}
                                        <div className={styles.meta}>
                                            <div style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{att.file.name}</div>
                                            <div style={{ color: '#888' }}>{Math.ceil(att.file.size / 1024)}KB</div>
                                        </div>
                                        <button className={styles.removeBtn} onClick={() => removeAttachment(att.id)}>移除</button>
                                    </div>
                                ))}
                            </div>
                        )}
                        <div className={styles.inputBar}>
                            <button
                                className={styles.micBtn}
                                title={showVoice ? '收起' : '展开语音'}
                                onClick={() => { setShowVoice((v) => !v); if (showEmoji) setShowEmoji(false) }}
                                style={{ color: isRecording ? '#ff4d4f' : undefined }}
                            >
                                <SoundOutline />
                            </button>
                            <div style={{ flex: 1, display: 'flex', gap: 8 }}>
                                <input
                                    type="text"
                                    ref={textareaRef}
                                    value={input}
                                    onChange={(e) => {
                                        setInput(e.target.value)
                                    }}
                                    onKeyDown={onKeyDown}
                                    placeholder={isLoading ? '等待回复中…' : '输入内容，Enter 发送'}
                                    disabled={isLoading}
                                    className={styles.textArea}
                                />
                                <button className={styles.sendBtn} onClick={sendMessage} disabled={isLoading || (!input.trim() && attachments.length === 0)}>发送</button>
                                <button className={`${styles.plusBtn} ${showEmoji ? styles.plusOpen : ''}`} onClick={() => { setShowEmoji((v) => !v); if (showVoice) setShowVoice(false) }} title={showEmoji ? '收起' : '展开'}>{showEmoji ? '+' : '+'}</button>
                            </div>
                        </div>
                        <div className={`${styles.expand} ${(showEmoji || showVoice) ? styles.expandOpen : ''}`}>
                            {showVoice && (
                                <>
                                    <div className={styles.voicePanel}>
                                        <button
                                            className={styles.voiceRoundBtn}
                                            onClick={async () => {
                                                if (isRecording) {
                                                    const rec = mediaRecorderRef.current
                                                    if (rec && rec.state !== 'inactive') {
                                                        try { rec.stop() } catch { /* ignore */ }
                                                    }
                                                    setIsRecording(false)
                                                    return
                                                }
                                                try {
                                                    const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
                                                    const chunks: BlobPart[] = []
                                                    const rec = new MediaRecorder(stream)
                                                    mediaRecorderRef.current = rec
                                                    rec.ondataavailable = (e) => {
                                                        if (e.data && e.data.size > 0) chunks.push(e.data)
                                                    }
                                                    rec.onstop = async () => {
                                                        const blob = new Blob(chunks, { type: 'audio/webm' })
                                                        const arrayBuffer = await blob.arrayBuffer()
                                                        const base64 = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)))
                                                        const dataUrl = `data:audio/webm;base64,${base64}`
                                                        const filename = `record_${Date.now()}.webm`
                                                        const item = { id: `${Date.now()}-${Math.random()}`, file: new File([blob], filename, { type: 'audio/webm' }), url: dataUrl, kind: 'audio' as const }
                                                        setAttachments([item])
                                                        setTimeout(() => { sendMessage() }, 0)
                                                        try { stream.getTracks().forEach(t => t.stop()) } catch { /* ignore */ }
                                                    }
                                                    rec.start()
                                                    setIsRecording(true)
                                                } catch {
                                                    alert('无法开始录音，请检查麦克风权限')
                                                }
                                            }}
                                        >{isRecording ? '停止' : '录音'}</button>
                                    </div>
                                </>
                            )}
                            {showEmoji && (
                                <>
                                    <div className={styles.grid}>
                                        <button className={styles.gridBtn} onClick={() => setShowEmoji(false)}>😊 表情</button>
                                        <button className={styles.gridBtn} onClick={() => imageInputRef.current?.click()}>🖼️ 相册</button>
                                        <button className={styles.gridBtn} onClick={() => fileInputRef.current?.click()}>📎 文件</button>
                                        <button className={styles.gridBtn} onClick={() => { }}>▶️ 视频</button>
                                        <button className={styles.gridBtn} onClick={() => { }}>📷 拍摄</button>
                                    </div>
                                    <div className={styles.emojiGrid}>
                                        {['😀', '😁', '😂', '🤣', '😊', '😍', '😘', '😎', '🙃', '😇', '🙂', '😌', '😋', '🤔', '🤨', '😴', '🤤', '😷', '🤒', '🤕', '👍', '👎', '👏', '🙏', '💪', '🔥', '✨', '🎉', '✅', '❌'].map((e) => (
                                            <button key={e} className={styles.emojiBtn} onClick={() => addEmoji(e)}>{e}</button>
                                        ))}
                                    </div>
                                </>
                            )}
                        </div>
                        <input ref={imageInputRef} onChange={onPickImages} type="file" accept="image/*" multiple className={styles.hiddenInput} />
                        <input ref={fileInputRef} onChange={onPickFiles} type="file" multiple className={styles.hiddenInput} />
                    </div>
                </div>
    </div>
  )
}

export default Index
